import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;

/**
 * 使用正确的算法解密EP: RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING
 */
public class DecryptEPWithOAEP {
    
    // 从加密数据.md中获取的数据
    private static final String EP_BASE64 = "qt0AJsNLEfayUx7S15jLfmQvMOpW6JJ+jCoxeXxn676R2OiN6xpLIQWSYe8ETFUF4+AaGrVY1wMCdyUPVaHM0J+8m+q/PUFgbiP3N8xSKQc4lIzzZuckbybYiFuLbEhcblmy162S5B70UJxzB6grhIVpsG/h0uw+JPaS2yTPpPVCiN/SImdOw2g12cun6niAwRZSQktZikzzbjwkRoiO8ehrwlAFJircnT1/1zba2oaGXLc/yU6cM2vWgJdyyoXJF4Mo/5XNBTDT+8yr1hPC5MKHWcTBB/isrRTD5CczInLgXHl48KKz18GkpPM7MML1GHb4pIjfTvu8hv/SLLW0sg==";
    
    private static final String PRIVATE_KEY_BASE64 = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCz8JyumzBRR1njdxPzCFpqWXrAUBiC4ycTbTDdWdpZkciwiXU5s/OxF5i7l+Hvwc9Ggjph/PKo7PpWhxZpzyEGpd6yVN9jAjJOt23o2TesgK8L/DAMhdJL8gNxKAQumbGF+ebMbcS8jWLxvDAqpmnEW8VdCLEjF6uqOPtcDmIkBF83W6oaeu32DzTr/NS16sUGQKxlflo9qPOl7VtcIsbR52klKK4uIyY23tWCouiyG84c/Uit+PleD5EYUGEu3p7IAAG5uJNzeUd0UjZDhy6x7ue+kGgcCmCNQ4zSS/bQHMknalwqJUvUSxtIf8dq+/D78m7d4Zt9n9ZD27t4Z2jHAgMBAAECggEAAr15RVdrpvE1NzeLADpyVghCzEbr+KJI6AzTn6tMneyQZ8/QDy7kWSAI3WJ0uFf1Nhepl/BoKZZiQYsRFk9nK1i/SWvtcu6HoZc9fzw/ksrq333ZpXcsOqfW0ZRQa/0/LNEfaKGLS2vDw/afrSaXmbvkB4SoXeZwYMk5Wq+FYxL/alrNpg/lzdvBlsCsTDA0G2RZrUVaO5yRTLRisBU+i8yORgnGkEwWvKpZYSFogCHSiYHiNXFy//C+sYWlK7DjmG8/+krKhqBRRfdeg7LFThHQpbEGTtueD57jw0PCo2yr6dqTvW9Qys+aWVNJk7RHNaI0yBFKWPadaHi3/olzkQKBgQDmz/FDpztS0fjKDIOjgDyE76Z6dRFenmKJM1eOFt+MniY6/vi4ylU51/Etm4k6dNJ1MVBoFfyT9X0U/4k7GNNUfIxMCJztUgY6EaCCt+09wk8pIvmOlRCmtxGwvmVC4nJVgUj3XJQ+wseblAkkW0+IuT3GKX0CdKFMU4q9aucLYwKBgQDHk3rQ8Ae4ci4oj+MehRI29SNpcXG6OHbrZ2EdsgqiFC1o/qv0269jtmCP7IqkGMdhTQrVetTHjZNZJH2bvUZ4o/0YT2+TTFPIkTb2/a0txUTBTKrbnAdXh/iPFZAGvBROEDN0MNKo/vGAfi0K836DeTyBIaYongm66Rn6pwnUTQKBgBveVaougfoxAhIbSrWuISCH8xjsE6nSA+G/Aj5Uwq8u1TzgVlWxkHLIgQVZt0sImfSufJ/kr7eJt42WgRJSoAmedC4mCBSbh8bxI+lEne+MC5TS9UDi/Ly0c/1cL8vQna93ScEcO4YMbJ97U1NBdyvx+eR4U/C89lDJ8YGHa9gzAoGAQ6sYsHFCXOKyDeTDoFyEUYgKqrzhT7/HaofR4Oy2OEBZKUl4anx2WnvC/+m3FG6mY7JoovuT29mABXCe+khR9aO8tBpy/WGa4t2B4nse1e8WIehp4i5kOuSKfZFVFUN+Kv3JRHMtakmO/v9JLHZlBhT8U9hh61GygOJ6gYdTiN0CgYAFz9iPy/xqLOUwiTNp3ImzhdZo9ol3Qlr9CfMWMFHqRA5AyYvly9ZzxTpUCpSA+qz6OXqAjJ0bhGQxW2KHpmcTyNGOPPca2vCaW8Mb1NTQueXpUBqX7alIkrRjUUyULteLb8FtyYl7mR3TVIu3FoO5anNwDZ+2y7R9WUEiOzY3NA==";
    
    public static void main(String[] args) {
        System.out.println("\n" + "=".repeat(80));
        System.out.println("           使用 RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING 解密 EP");
        System.out.println("=".repeat(80) + "\n");
        
        try {
            // 1. 准备私钥
            byte[] privateKeyBytes = Base64.getDecoder().decode(PRIVATE_KEY_BASE64);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            
            System.out.println("✅ 私钥加载成功");
            System.out.println("私钥算法: " + privateKey.getAlgorithm());
            System.out.println("私钥格式: " + privateKey.getFormat());
            
            // 2. 解密EP（使用OAEP填充）
            byte[] epEncrypted = Base64.getDecoder().decode(EP_BASE64);
            System.out.println("\nEP加密数据长度: " + epEncrypted.length + " 字节");
            
            // 尝试使用 OAEP with SHA-256
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] epDecrypted = cipher.doFinal(epEncrypted);
            
            System.out.println("\n" + "=".repeat(80));
            System.out.println("🎉 EP 解密成功！");
            System.out.println("=".repeat(80));
            System.out.println("解密后长度: " + epDecrypted.length + " 字节\n");
            
            // 3. 分析解密后的数据
            System.out.println("-".repeat(80));
            System.out.println("EP 解密后的完整内容:");
            System.out.println("-".repeat(80));
            printHexDump(epDecrypted);
            
            System.out.println("\n" + "-".repeat(80));
            System.out.println("结构分析:");
            System.out.println("-".repeat(80));
            
            // 尝试不同的解析方式
            if (epDecrypted.length >= 32) {
                System.out.println("\n假设1: 前32字节是AES密钥");
                byte[] possibleKey = Arrays.copyOfRange(epDecrypted, 0, 32);
                System.out.println("密钥(HEX): " + bytesToHex(possibleKey));
                System.out.println("熵值: " + String.format("%.2f", calculateEntropy(possibleKey)) + " / 8.0");
            }
            
            if (epDecrypted.length >= 48) {
                System.out.println("\n假设2: [0:32]是密钥, [32:48]是IV");
                byte[] possibleKey = Arrays.copyOfRange(epDecrypted, 0, 32);
                byte[] possibleIV = Arrays.copyOfRange(epDecrypted, 32, 48);
                System.out.println("密钥(HEX): " + bytesToHex(possibleKey));
                System.out.println("IV(HEX):   " + bytesToHex(possibleIV));
            }
            
            if (epDecrypted.length >= 16) {
                System.out.println("\n假设3: 前16字节是IV");
                byte[] possibleIV = Arrays.copyOfRange(epDecrypted, 0, 16);
                System.out.println("IV(HEX): " + bytesToHex(possibleIV));
            }
            
            // 4. 尝试解析为文本
            System.out.println("\n" + "-".repeat(80));
            System.out.println("尝试解析为文本:");
            System.out.println("-".repeat(80));
            
            try {
                String utf8 = new String(epDecrypted, "UTF-8");
                System.out.println("UTF-8: " + utf8);
            } catch (Exception e) {
                System.out.println("UTF-8: (无法解析为有效文本)");
            }
            
            try {
                String ascii = new String(epDecrypted, "ASCII");
                if (ascii.matches("^[\\x20-\\x7E]*$")) {
                    System.out.println("ASCII: " + ascii);
                } else {
                    System.out.println("ASCII: (包含非打印字符)");
                }
            } catch (Exception e) {
                System.out.println("ASCII: (无法解析)");
            }
            
            System.out.println("\n" + "=".repeat(80));
            System.out.println("💡 EP 解密后的原始数据就在上面！");
            System.out.println("=".repeat(80) + "\n");
            
        } catch (javax.crypto.BadPaddingException e) {
            System.err.println("\n❌ 解密失败: 填充错误");
            System.err.println("可能的原因:");
            System.err.println("  1. 私钥不匹配（这不是加密EP的公钥对应的私钥）");
            System.err.println("  2. EP数据已损坏");
            System.err.println("  3. 加密算法参数不正确");
            System.err.println("\n错误详情: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("\n❌ 发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    private static void printHexDump(byte[] data) {
        for (int i = 0; i < data.length; i += 16) {
            System.out.print(String.format("%04X: ", i));
            
            // Hex
            for (int j = 0; j < 16; j++) {
                if (i + j < data.length) {
                    System.out.print(String.format("%02X ", data[i + j]));
                } else {
                    System.out.print("   ");
                }
                if (j == 7) System.out.print(" ");
            }
            
            // ASCII
            System.out.print(" |");
            for (int j = 0; j < 16 && i + j < data.length; j++) {
                byte b = data[i + j];
                System.out.print((b >= 32 && b < 127) ? (char) b : '.');
            }
            System.out.println("|");
        }
    }
    
    private static double calculateEntropy(byte[] data) {
        int[] counts = new int[256];
        for (byte b : data) {
            counts[b & 0xFF]++;
        }
        
        double entropy = 0.0;
        for (int count : counts) {
            if (count > 0) {
                double p = (double) count / data.length;
                entropy -= p * (Math.log(p) / Math.log(2));
            }
        }
        return entropy;
    }
}



